"""
F1 scores
F1 = 2 * precision * recall / (precision + recall)

Macro-F1和Micro-F1是相对于多标签分类而言的。
Micro-F1，计算出所有类别总的Precision和Recall，然后计算F1。
Macro-F1，计算出每一个类的Precison和Recall后计算F1，最后将F1平均。
"""
from keras.metrics import Precision, Recall
from sklearn.metrics import recall_score, precision_score, f1_score


def get_data():
    """

    :return:
    """
    y_true = [0, 0, 1, 1, 0, 0, 1]
    y_pred = [0, 1, 0, 1, 0, 1, 0]

    return y_true, y_pred


def compute_f1(y_true, y_pred):
    """

    :param y_true:
    :param y_pred:
    :return:
    """
    keras_precision = Precision()
    keras_precision.update_state(y_true=y_true, y_pred=y_pred)
    keras_precision_scores = keras_precision.result().numpy()

    keras_recall = Recall()
    keras_recall.update_state(y_true=y_true, y_pred=y_pred)
    keras_recall_scores = keras_recall.result().numpy()

    sklearn_precision_scores = precision_score(y_true=y_true, y_pred=y_pred)
    sklearn_recall_scores = recall_score(y_true=y_true, y_pred=y_pred)

    keras_f1 = 2 * keras_precision_scores * keras_recall_scores / \
               (keras_precision_scores + keras_recall_scores)
    sklearn_f1 = 2 * sklearn_precision_scores * sklearn_recall_scores / \
                 (sklearn_precision_scores + sklearn_recall_scores)

    return keras_f1, sklearn_f1


def run():
    """
    主程序
    :return:
    """
    y_true, y_pred = get_data()

    # 自己算
    keras_f1, sklearn_f1 = compute_f1(y_true=y_true, y_pred=y_pred)

    f1_scores = f1_score(y_true=y_true, y_pred=y_pred)

    info = 'F1 scores: f1: {}, keras: {}, sklearn: {}'.\
        format(f1_scores, keras_f1, sklearn_f1)
    print(info)


if __name__ == '__main__':
    run()
